package com.common.serialize.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import com.common.entity.RPCRequest;
import com.common.entity.RPCResponse;
import com.common.serialize.CommonSerializer;
import com.common.serialize.SerializerCode;
import lombok.extern.slf4j.Slf4j;

/**
 * @author Zixiang Hu
 * @description 实现Json序列化
 * @create 2021-02-27-19:10
 */
@Slf4j
public class JsonSerializer implements CommonSerializer {
    @Override
    public byte[] serialize(Object obj) {
        byte[] bytes = JSONObject.toJSONBytes(obj);
        return bytes;
    }

    /**
     * @param bytes
     * @param clazz 针对RPC而言，传入的clazz要不是Response要不是Request
     * @return
     */
    @Override
    public Object deserialize(byte[] bytes, Class<?> clazz) {
        Object parseObject = JSONObject.parseObject(bytes, clazz);
        if (parseObject instanceof RPCRequest) {
            handleRequest((RPCRequest) parseObject);
            return parseObject;
        } else if (parseObject instanceof RPCResponse) {
            handleResponse((RPCResponse) parseObject);
            return parseObject;
        } else {
            log.error("JsonSerializer传入的发序列化类型暂时未定义，序列化失败");
            return null;
        }
    }

    /**
     * 这个函数的目的与handleRequest一样
     * 主要作用是将RPCResponse中的data解析为原来的类型
     *
     * @param response
     */
    private void handleResponse(RPCResponse response) {
        if (response.getData() == null)
            return;
        Class<?> dataType = response.getDataType();
        Object responseData = response.getData();
        if (!responseData.getClass().isAssignableFrom(dataType)) {
            Object o = JSON.toJavaObject((JSON) responseData, dataType);
            response.setData(o);
        }
    }

    /**
     * 这里由于使用JSON序列化和反序列化Object数组，无法保证反序列化后仍然为原实例类型
     * 需要重新判断处理
     *
     * @param request
     */
    private void handleRequest(RPCRequest request) {
        // 如果本身没有参数，直接返回即可
        if (request.getParams().length == 0)
            return;
        Object[] params = new Object[request.getParams().length];
        Class<?>[] paramsTypes = request.getParamsTypes();
        for (int i = 0; i < params.length; i++) {
            Class<?> paramsType = paramsTypes[i];
            // 如果不是基本类型，还需要进一步解析
            if (!request.getParams()[i].getClass().isAssignableFrom(paramsType)) {
                params[i] = JSON.toJavaObject((JSON) request.getParams()[i], paramsType);
            } else
                params[i] = request.getParams()[i]; // 如果是基本类型，则直接赋值即可
        }
        request.setParams(params);
    }

    @Override
    public int getCode() {
        return SerializerCode.valueOf("JSON").getCode();
    }
}
